from flask import Blueprint, render_template, abort, jsonify, request, make_response
from flask_login import login_required
from .. import db
from ..models import Field, Sensor, Task, Role
from datetime import datetime, timedelta
import math
import random
from shapely.geometry import Polygon, Point

bp = Blueprint('main', __name__)

@bp.route('/')
@login_required
def index():
    """首页"""
    # 获取统计数据
    field_count = len(db.fields)
    total_area = round(sum(field.area for field in db.fields), 2)  # 保留两位小数
    device_count = len(db.sensors)
    online_count = sum(1 for device in db.sensors if device.is_online)
    
    # 获取任务统计
    tasks = db.tasks or []
    pending_tasks = sum(1 for task in tasks 
        if task.status in ['pending', 'in_progress']
        and not task.title.startswith('设备维护')
        and not task.title.startswith('施肥任务')
        and not task.title.startswith('灌溉任务')
    )
    completed_tasks = sum(1 for task in tasks 
        if task.status == 'completed'
        and not task.title.startswith('设备维护')
        and not task.title.startswith('施肥任务')
        and not task.title.startswith('灌溉任务')
    )
    
    # 获取最近的任务（按优先级和创建时间排序）
    recent_tasks = sorted(
        [task for task in tasks if task.status != 'completed' 
         and not task.title.startswith('设备维护')
         and not task.title.startswith('施肥任务')
         and not task.title.startswith('灌溉任务')],
        key=lambda x: (x.priority, x.created_at),
        reverse=True
    )[:5]  # 只显示前5个任务
    
    # 获取最近24小时的数据
    now = datetime.now()
    start_time = now - timedelta(hours=24)
    
    # 准备图表数据
    timestamps = []
    temperature_data = []
    humidity_data = []
    soil_moisture_data = []
    
    # 生成合理的模拟数据
    for i in range(24):
        time = start_time + timedelta(hours=i)
        
        timestamps.append(time.strftime('%H:00'))
        
        # 生成温度数据（白天温度较高，夜间温度较低）
        hour = time.hour
        base_temp = 25  # 基础温度
        temp_variation = 8  # 温度变化幅度
        noise = random.uniform(-1, 1)  # 随机波动
        
        if 6 <= hour <= 18:  # 白天
            temp = base_temp + temp_variation * math.sin((hour - 6) * math.pi / 12) + noise
        else:  # 夜间
            if hour < 6:
                temp = base_temp - temp_variation/2 + noise
            else:  # hour > 18
                temp = base_temp - temp_variation/2 * (1 + (hour - 18)/6) + noise
        
        temperature_data.append(round(temp, 1))
        
        # 生成湿度数据（与温度呈负相关）
        base_humidity = 60  # 基础湿度
        humidity_variation = 30  # 湿度变化幅度
        humidity_noise = random.uniform(-5, 5)
        humidity = base_humidity - (temp - base_temp) * 2 + humidity_noise
        humidity = min(max(humidity, 30), 90)  # 限制在30-90%范围内
        humidity_data.append(round(humidity, 1))
        
        # 生成土壤湿度数据（较为稳定，有缓慢变化）
        base_moisture = 45  # 基础土壤湿度
        moisture_variation = 15  # 土壤湿度变化幅度
        moisture_trend = math.sin(i * math.pi / 12)  # 缓慢变化趋势
        moisture_noise = random.uniform(-2, 2)
        moisture = base_moisture + moisture_variation * moisture_trend + moisture_noise
        moisture = min(max(moisture, 20), 80)  # 限制在20-80%范围内
        soil_moisture_data.append(round(moisture, 1))
    
    return render_template('index.html',
        field_count=field_count,
        total_area=total_area,
        device_count=device_count,
        online_count=online_count,
        pending_tasks=pending_tasks,
        completed_tasks=completed_tasks,
        recent_tasks=recent_tasks,
        timestamps=timestamps,
        temperature_data=temperature_data,
        humidity_data=humidity_data,
        soil_moisture_data=soil_moisture_data
    )

@bp.route('/fields')
@login_required
def field_management():
    """农田管理页面"""
    fields = [field.to_dict() for field in db.fields]
    # 调试输出
    for field in fields:
        print(f"Field {field['id']}: {field['name']}, boundary: {field['boundary']}")
    return render_template('field/index.html',
        fields=fields,
        active_page='fields'
    )

@bp.route('/device-management')
@login_required
def device_management():
    """设备管理"""
    # 获取所有设备和农田信息
    devices = [device.to_dict() for device in db.sensors]
    fields = {field.id: field.to_dict() for field in db.fields}
    
    # 调试输出
    print("设备数量:", len(devices))
    print("农田数量:", len(fields))
    
    # 为没有位置信息的设备生成随机位置
    for device in devices:
        field_id = device.get('field_id')
        if field_id:
            field = fields.get(device['field_id'])
            if field and field.get('boundary'):
                # 确保边界至少有3个点
                if len(field['boundary']) >= 3:
                    # 无论是否有位置信息，都重新生成位置
                    device['location'] = generate_random_location(field['boundary'])
                    print(f"为设备 {device['name']} 生成位置:", device['location'])
                else:
                    # 如果没有有效边界，使用农田中心点附近的随机位置
                    center_lat = sum(p[0] for p in field['boundary']) / len(field['boundary'])
                    center_lng = sum(p[1] for p in field['boundary']) / len(field['boundary'])
                    device['location'] = {
                        'lat': center_lat + random.uniform(-0.0001, 0.0001),
                        'lng': center_lng + random.uniform(-0.0001, 0.0001)
                    }
                    print(f"为设备 {device['name']} 生成中心点位置:", device['location'])
        else:
            print(f"设备 {device['name']} 没有关联农田")
    
    # 检查物联网卡状态
    now = datetime.now()
    for device in devices:
        if device.get('sim_expire_date'):
            expire_date = datetime.fromisoformat(device['sim_expire_date'])
            days_remaining = (expire_date - now).days
            
            if days_remaining <= 0:
                device['sim_status'] = 'expired'
            elif days_remaining <= 30:
                device['sim_status'] = 'expiring'
            else:
                device['sim_status'] = 'active'
    
    # 统计信息
    stats = {
        'total': len(devices),
        'online': sum(1 for d in devices if d['is_online']),
        'offline': sum(1 for d in devices if not d['is_online']),
        'sim_expired': sum(1 for d in devices if d.get('sim_status') == 'expired'),
        'sim_expiring': sum(1 for d in devices if d.get('sim_status') == 'expiring')
    }
    
    return render_template('device/index.html',
        devices=devices,
        fields=fields,
        stats=stats
    )

@bp.route('/decision')
@login_required
def decision():
    """决策支持"""
    # 检查是否是AJAX请求
    is_ajax = request.args.get('ajax', '0') == '1'
    
    # 获取所有农田信息
    fields = [field.to_dict() for field in db.fields]
    
    # 获取传感器数据
    sensors = [sensor.to_dict() for sensor in db.sensors]
    soil_sensors = [s for s in sensors if s['device_type'] == 'soil_moisture']
    weather_stations = [s for s in sensors if s['device_type'] == 'weather']
    
    # 获取当前作物生长阶段
    current_crop = fields[0]['current_crop'] if fields else '玉米'  # 默认作物为玉米
    growth_stage = '抽穗期'  # 这里应该根据实际种植日期计算
    
    # 获取天气预报数据（示例数据）
    weather_forecast = {
        'today': {'temp': 28, 'humidity': 65, 'rainfall': 0, 'wind': 2.3},
        'tomorrow': {'temp': 29, 'humidity': 60, 'rainfall': 0, 'wind': 3.1},
        'day_after': {'temp': 27, 'humidity': 75, 'rainfall': 15, 'wind': 2.8}
    }
    
    # 获取最近的土壤墒情数据
    now = datetime.now()
    start_time = now - timedelta(hours=24)
    soil_data = []
    for sensor in soil_sensors:
        data = generate_mock_data(sensor, start_time, now, 'moisture')
        if data:
            soil_data.extend(data)
    
    # 生成示例决策数据
    decisions = {
        'spray': {  # 施药决策
            'status': '需要施药',
            'severity': 0.75,
            'distribution': '主要分布在农田东北部',
            'recommendation': f'当前{current_crop}处于{growth_stage}，易发生病虫害。建议使用20%吡虫啉可湿性粉剂进行定点喷洒，稀释500倍，每亩用药量2.5千克。明日风速{weather_forecast["tomorrow"]["wind"]}m/s，适合喷药。',
            'prescription_map': 'spray_prescription.png',
            'details': [
                {
                    'area': '东北部', 
                    'issue': '玉米螟虫害', 
                    'severity': '严重', 
                    'coverage': '约12亩',
                    'action': '重点喷洒，用药量30千克',
                    'timing': '建议明日上午8点前完成喷药',
                    'method': '采用无人机喷洒，飞行高度3-4米'
                },
                {
                    'area': '中部', 
                    'issue': '杂草滋生', 
                    'severity': '中等', 
                    'coverage': '约8亩',
                    'action': '适量喷洒，用药量15千克',
                    'timing': '建议明日上午10点前完成喷药',
                    'method': '采用无人机喷洒，飞行高度2-3米'
                }
            ]
        },
        'fertilizer': {  # 施肥决策
            'status': '需要追肥',
            'growth_status': 0.65,
            'recommendation': f'当前{current_crop}处于{growth_stage}，养分需求量大。建议进行分区变量施肥，重点关注西部区域，使用含氮量≥40%的尿素。预计3天后有降雨{weather_forecast["day_after"]["rainfall"]}mm，可配合降雨进行施肥。',
            'prescription_map': 'fertilizer_prescription.png',
            'details': [
                {
                    'area': '西部',
                    'nutrient': '尿素',
                    'amount': '30kg/亩',
                    'coverage': '约15亩',
                    'total': '450kg',
                    'reason': '叶片发黄，生长偏弱',
                    'method': '采用撒肥机深施，确保肥料进入土层10-15cm',
                    'notes': '施肥后及时镇压，防止肥料流失'
                },
                {
                    'area': '东部',
                    'nutrient': '复合肥(15-15-15)',
                    'amount': '20kg/亩',
                    'coverage': '约10亩',
                    'total': '200kg',
                    'reason': '营养需求均衡',
                    'method': '采用撒肥机浅施，确保肥料进入土层5-10cm',
                    'notes': '注意均匀撒施，避免局部过量'
                }
            ]
        },
        'irrigation': {  # 灌溉决策
            'status': '建议灌溉',
            'soil_moisture': 0.35,
            'weather_forecast': '未来3天无降雨',
            'recommendation': f'当前{current_crop}处于{growth_stage}，日需水量4-5mm。土壤墒情偏低，未来3天无明显降雨，建议及时灌溉。灌溉深度控制在30-40cm，预计灌溉后土壤含水量可维持7-10天。',
            'prescription_map': 'irrigation_prescription.png',
            'details': [
                {
                    'area': '南部',
                    'moisture': '偏低(25%)',
                    'amount': '30mm',
                    'coverage': '约20亩',
                    'total': '600m³',
                    'timing': '建议今日灌溉',
                    'method': '采用喷灌系统，分3次完成灌溉',
                    'duration': '每次灌溉时间40-50分钟',
                    'notes': '控制好灌溉速度，避免地表径流'
                },
                {
                    'area': '北部',
                    'moisture': '适中(45%)',
                    'amount': '15mm',
                    'coverage': '约15亩',
                    'total': '225m³',
                    'timing': '建议3天后灌溉',
                    'method': '采用喷灌系统，分2次完成灌溉',
                    'duration': '每次灌溉时间30-40分钟',
                    'notes': '注意观察土壤渗透情况，适时调整灌溉量'
                }
            ]
        }
    }
    
    # 如果是AJAX请求，返回JSON数据
    if is_ajax:
        return jsonify({
            'decisions': decisions
        })
    
    # 否则返回完整页面
    return render_template('decision/index.html', 
        fields=fields,
        decisions=decisions
    )

@bp.route('/task-management')
@login_required
def task_management():
    """任务管理"""
    return render_template('task/index.html',
        tasks=[task.to_dict() for task in (db.tasks or [])],  # 添加空列表作为默认值
        fields=[field.to_dict() for field in db.fields]
    )

@bp.route('/field-management/view/<field_id>')
@login_required
def view_field(field_id):
    field = Field.find_by_id(field_id)
    if not field:
        abort(404)
    return render_template('field/view.html', field=field.to_dict())

@bp.route('/field-management/edit/<field_id>')
@login_required
def edit_field(field_id):
    field = Field.find_by_id(field_id)
    if not field:
        abort(404)
    return render_template('field/edit.html', field=field.to_dict())

@bp.route('/device-management/data/<device_id>')
@login_required
def device_data(device_id):
    device = Sensor.find_by_id(device_id)
    if not device:
        abort(404)
    # 获取设备所属的农田信息
    field = Field.find_by_id(device.field_id) if device.field_id else None
    
    # 获取最近24小时的默认数据
    end_time = datetime.now()
    start_time = end_time - timedelta(hours=24)
    
    # 生成初始数据
    initial_data = generate_mock_data(device, start_time, end_time, 'all')
    
    return render_template('device/data.html', 
        device=device.to_dict(),
        field=field.to_dict() if field else None,
        initial_data=initial_data
    )

@bp.route('/device-management/edit/<device_id>')
@login_required
def edit_device(device_id):
    device = Sensor.find_by_id(device_id)
    if not device:
        abort(404)
    return render_template('device/edit.html', device=device.to_dict())

@bp.route('/user-management')
@login_required
def user_management():
    """用户管理"""
    permission_names = {
        Role.VIEW: '查看',
        Role.MANAGE_FIELDS: '管理农田',
        Role.MANAGE_DEVICES: '管理设备',
        Role.MANAGE_TASKS: '管理任务',
        Role.MANAGE_USERS: '管理用户',
        Role.MANAGE_ROLES: '管理角色'
    }
    
    return render_template('user/index.html',
        users=[user.to_dict() for user in db.users],
        roles=[role.to_dict() for role in db.roles],
        all_permissions=list(permission_names.keys()),
        permission_names=permission_names
    )

@bp.route('/api/devices/<device_id>/data')
@login_required
def get_device_data(device_id):
    try:
        device = Sensor.find_by_id(device_id)
        if not device:
            return jsonify({'error': '设备不存在'}), 404
        
        # 获取查询参数
        time_range = request.args.get('time_range', '24h')
        data_type = request.args.get('data_type', 'all')
        
        print(f"Generating data for device {device_id}, time_range: {time_range}, data_type: {data_type}")  # 调试日志
        
        # 计算时间范围
        end_time = datetime.now()  # 使用本地时间而不是UTC时间
        if time_range == 'custom':
            try:
                start_time = datetime.fromisoformat(request.args.get('start_time').replace('Z', '+00:00'))
                end_time = datetime.fromisoformat(request.args.get('end_time').replace('Z', '+00:00'))
            except (ValueError, TypeError) as e:
                print(f"Error parsing time: {e}")  # 调试日志
                return jsonify({'error': '无效的时间格式'}), 400
        else:
            # 解析时间范围
            range_map = {
                '24h': timedelta(hours=24),
                '7d': timedelta(days=7),
                '30d': timedelta(days=30)
            }
            start_time = end_time - range_map.get(time_range, timedelta(hours=24))
        
        # 生成模拟数据
        data = generate_mock_data(device, start_time, end_time, data_type)
        print(f"Generated {len(data)} data points")  # 调试日志
        
        if not data:
            print("Warning: No data generated")
            return jsonify([])  # 返回空数组而不是错误
        
        return jsonify(data)
    except Exception as e:
        print(f"Error generating data: {e}")
        return jsonify({'error': '生成数据时发生错误'}), 500

@bp.route('/api/devices/<device_id>/data/export')
@login_required
def export_device_data(device_id):
    device = Sensor.find_by_id(device_id)
    if not device:
        abort(404)
    
    # 获取数据（复用获取数据的逻辑）
    time_range = request.args.get('time_range', '24h')
    data_type = request.args.get('data_type', 'all')
    
    # 计算时间范围
    end_time = datetime.utcnow()
    if time_range == 'custom':
        try:
            start_time = datetime.fromisoformat(request.args.get('start_time'))
            end_time = datetime.fromisoformat(request.args.get('end_time'))
        except (ValueError, TypeError):
            return jsonify({'error': '无效的时间格式'}), 400
    else:
        range_map = {
            '24h': timedelta(hours=24),
            '7d': timedelta(days=7),
            '30d': timedelta(days=30)
        }
        start_time = end_time - range_map.get(time_range, timedelta(hours=24))
    
    data = generate_mock_data(device, start_time, end_time, data_type)
    
    # 生成CSV文件内容
    output = 'timestamp,data_type,value\n'
    for item in data:
        output += f"{item['timestamp']},{item['data_type']},{item['value']}\n"
    
    # 返回CSV文件
    response = make_response(output)
    response.headers['Content-Type'] = 'text/csv'
    response.headers['Content-Disposition'] = f'attachment; filename=device_{device_id}_data.csv'
    return response

def generate_mock_data(device, start_time, end_time, data_type):
    """生成模拟数据"""
    data = []
    current_time = start_time
    
    # 确保时间范围有效
    if end_time < start_time:
        print("Warning: end_time is before start_time, swapping times")
        start_time, end_time = end_time, start_time
    
    # 限制数据点数量，避免生成太多数据
    time_diff = end_time - start_time
    if time_diff.total_seconds() > 30 * 24 * 3600:  # 如果超过30天
        interval = timedelta(hours=1)  # 每小时一个数据点
    elif time_diff.total_seconds() > 7 * 24 * 3600:  # 如果超过7天
        interval = timedelta(minutes=30)  # 每30分钟一个数据点
    else:
        interval = timedelta(minutes=5)  # 每5分钟一个数据点
    
    # 根据设备类型确定数据类型
    device_type = device.get('device_type', '') if isinstance(device, dict) else device.device_type
    
    if device_type == 'soil_moisture':
        data_types = ['moisture', 'temperature'] if data_type == 'all' else [data_type]
        value_ranges = {
            'moisture': (20, 80),  # 土壤湿度范围：20%-80%
            'temperature': (10, 30)  # 土壤温度范围：10-30°C
        }
    elif device_type == 'weather':  # weather station
        data_types = ['temperature', 'humidity', 'rainfall'] if data_type == 'all' else [data_type]
        value_ranges = {
            'temperature': (15, 35),  # 气温范围：15-35°C
            'humidity': (30, 90),     # 湿度范围：30%-90%
            'rainfall': (0, 50)       # 降雨量范围：0-50mm
        }
    else:
        print(f"Unknown device type: {device_type}")  # 调试日志
        data_types = []
        value_ranges = {}
    
    print(f"Data types to generate: {data_types}")  # 调试日志
    
    # 生成数据点
    while current_time <= end_time:
        for dtype in data_types:
            if dtype in value_ranges:
                min_val, max_val = value_ranges[dtype]
                # 使用正弦函数生成周期性数据
                hour = current_time.hour + current_time.minute / 60
                base_value = (max_val + min_val) / 2
                amplitude = (max_val - min_val) / 2
                value = base_value + amplitude * math.sin(hour * math.pi / 12)
                # 添加随机波动
                value += random.uniform(-2, 2)
                value = max(min_val, min(max_val, value))
                
                data.append({
                    'timestamp': current_time.isoformat(),
                    'data_type': dtype,
                    'value': round(value, 2)
                })
        
        current_time += interval
    
    print(f"Generated {len(data)} data points")  # 调试日志
    return data

def generate_random_location(boundary):
    """在农田边界内生成随机位置"""
    try:
        # 确保边界坐标是正确的格式 [[lat, lng], ...]
        formatted_boundary = []
        for point in boundary:
            if len(point) >= 2:
                # 如果坐标是 [lng, lat] 格式，需要转换为 [lat, lng]
                if abs(point[0]) > 90:  # 经度值大于90度，说明是 [lng, lat] 格式
                    formatted_boundary.append([point[1], point[0]])
                else:
                    formatted_boundary.append(point)
        
        # 创建多边形
        poly = Polygon([(p[1], p[0]) for p in formatted_boundary])  # 转换为 (lng, lat) 格式
        
        # 获取多边形的边界框
        minx, miny, maxx, maxy = poly.bounds
        
        # 尝试生成在多边形内的随机点
        attempts = 0
        max_attempts = 100  # 最大尝试次数
        while True:
            attempts += 1
            point = Point([random.uniform(minx, maxx), random.uniform(miny, maxy)])
            if poly.contains(point):
                # 返回正确的经纬度格式
                return {'lat': point.y, 'lng': point.x}
            elif attempts >= max_attempts:
                # 如果多次尝试失败，返回多边形中心点附近的随机点
                center = poly.centroid
                return {
                    'lat': center.y + random.uniform(-0.0001, 0.0001),
                    'lng': center.x + random.uniform(-0.0001, 0.0001)
                }
    except Exception as e:
        print(f"Error generating random location: {str(e)}")
        try:
            # 计算边界的简单中心点
            center_lat = sum(p[0] for p in formatted_boundary) / len(formatted_boundary)
            center_lng = sum(p[1] for p in formatted_boundary) / len(formatted_boundary)
            return {
                'lat': center_lat + random.uniform(-0.0001, 0.0001),
                'lng': center_lng + random.uniform(-0.0001, 0.0001)
            }
        except:
            # 如果所有方法都失败，返回一个默认位置
            print("无法生成有效位置，使用默认位置")
            return {'lat': 35.86166, 'lng': 104.195397} 